/**
 * Custom implementation of {@link Ext.menu.Menu} that has preconfigured items
 * for entering numeric range comparison values: less-than, greater-than, and
 * equal-to. This is used internally by {@link Ext.ux.grid.filter.NumericFilter}
 * to create its menu.
 */
Ext.define('Ext.ux.grid.menu.RangeMenu', {
	extend : 'Ext.menu.Menu',

	/**
	 * @cfg {String} fieldCls The Class to use to construct each field item
	 *      within this menu Defaults to:
	 * 
	 * <pre>
	 * fieldCls : Ext.form.field.Number
	 * </pre>
	 */
	fieldCls : 'Ext.form.field.Number',

	/**
	 * @cfg {Object} fieldCfg The default configuration options for any field
	 *      item unless superseded by the <code>{@link #fields}</code>
	 *      configuration. Defaults to:
	 * 
	 * <pre>
	 * fieldCfg : {
	 * }
	 * </pre>
	 * 
	 * Example usage:
	 * 
	 * <pre><code>
	 * 	fieldCfg : {
	 * 	width: 150,
	 * 	},
	 * </code></pre>
	 */

	/**
	 * @cfg {Object} fields The field items may be configured individually
	 *      Defaults to <tt>undefined</tt>. Example usage:
	 * 
	 * <pre><code>
	 * 	fields : {
	 * 	gt: { // override fieldCfg options
	 * 	    width: 200,
	 * 	    fieldCls: Ext.ux.form.CustomNumberField // to override default {@link #fieldCls}
	 * 	}
	 * 	},
	 * </code></pre>
	 */

	/**
	 * @cfg {Object} itemIconCls The itemIconCls to be applied to each
	 *      comparator field item. Defaults to:
	 * 
	 * <pre>
	 * 	itemIconCls : {
	 * 	gt : 'ux-rangemenu-gt',
	 * 	lt : 'ux-rangemenu-lt',
	 * 	eq : 'ux-rangemenu-eq'
	 * 	}
	 * </pre>
	 */
	itemIconCls : {
		gt : 'ux-rangemenu-gt',
		lt : 'ux-rangemenu-lt',
		eq : 'ux-rangemenu-eq'
	},

	/**
	 * @cfg {Object} fieldLabels Accessible label text for each comparator field
	 *      item. Can be overridden by localization files. Defaults to:
	 * 
	 * <pre>
	 * 	fieldLabels : {
	 * 	 gt: 'Greater Than',
	 * 	 lt: 'Less Than',
	 * 	 eq: 'Equal To'
	 * 	}
	 * </pre>
	 */
	fieldLabels : {
		gt : 'Greater Than',
		lt : 'Less Than',
		eq : 'Equal To'
	},

	/**
	 * @cfg {Object} menuItemCfgs Default configuration options for each menu
	 *      item Defaults to:
	 * 
	 * <pre>
	 * 	menuItemCfgs : {
	 * 	emptyText: 'Enter Filter Text...',
	 * 	selectOnFocus: true,
	 * 	width: 125
	 * 	}
	 * </pre>
	 */
	menuItemCfgs : {
		emptyText : 'Enter Number...',
		selectOnFocus : false,
		width : 155
	},

	/**
	 * @cfg {Array} menuItems The items to be shown in this menu. Items are
	 *      added to the menu according to their position within this array.
	 *      Defaults to:
	 * 
	 * <pre>
	 * menuItems : ['lt', 'gt', '-', 'eq']
	 * </pre>
	 */
	menuItems : ['lt', 'gt', '-', 'eq'],

	plain : true,

	constructor : function(config) {
		var me = this, fields, fieldCfg, i, len, item, cfg, Cls;

		me.callParent(arguments);

		fields = me.fields = me.fields || {};
		fieldCfg = me.fieldCfg = me.fieldCfg || {};

		me.addEvents(
				/**
				 * @event update Fires when a filter configuration has changed
				 * @param {Ext.ux.grid.filter.Filter}
				 *            this The filter object.
				 */
				'update');

		me.updateTask = Ext.create('Ext.util.DelayedTask', me.fireUpdate, me);

		for (i = 0, len = me.menuItems.length; i < len; i++) {
			item = me.menuItems[i];
			if (item !== '-') {
				// defaults
				cfg = {
					itemId : 'range-' + item,
					enableKeyEvents : true,
					hideEmptyLabel : false,
					labelCls : 'ux-rangemenu-icon ' + me.itemIconCls[item],
					labelSeparator : '',
					labelWidth : 29,
					listeners : {
						scope : me,
						change : me.onInputChange,
						keyup : me.onInputKeyUp,
						el : {
							click : this.stopFn
						}
					},
					activate : Ext.emptyFn,
					deactivate : Ext.emptyFn
				};
				Ext.apply(cfg,
						// custom configs
						Ext.applyIf(fields[item] || {}, fieldCfg[item]),
						// configurable defaults
						me.menuItemCfgs);
				Cls = cfg.fieldCls || me.fieldCls;
				item = fields[item] = Ext.create(Cls, cfg);
			}
			me.add(item);
		}
	},

	stopFn : function(e) {
		e.stopPropagation();
	},

	/**
	 * @private called by this.updateTask
	 */
	fireUpdate : function() {
		this.fireEvent('update', this);
	},

	/**
	 * Get and return the value of the filter.
	 * 
	 * @return {String} The value of this filter
	 */
	getValue : function() {
		var result = {}, fields = this.fields, key, field;

		for (key in fields) {
			if (fields.hasOwnProperty(key)) {
				field = fields[key];
				if (field.isValid() && field.getValue() !== null) {
					result[key] = field.getValue();
				}
			}
		}
		return result;
	},

	/**
	 * Set the value of this menu and fires the 'update' event.
	 * 
	 * @param {Object}
	 *            data The data to assign to this menu
	 */
	setValue : function(data) {
		var me = this, fields = me.fields, key, field;

		for (key in fields) {
			if (fields.hasOwnProperty(key)) {
				// Prevent field's change event from tiggering a Store filter.
				// The final upate event will do that
				field = fields[key];
				field.suspendEvents();
				field.setValue(key in data ? data[key] : '');
				field.resumeEvents();
			}
		}

		// Trigger the filering of the Store
		me.fireEvent('update', me);
	},

	/**
	 * @private Handler method called when there is a keyup event on an input
	 *          item of this menu.
	 */
	onInputKeyUp : function(field, e) {
		if (e.getKey() === e.RETURN && field.isValid()) {
			e.stopEvent();
			this.hide();
		}
	},

	/**
	 * @private Handler method called when the user changes the value of one of
	 *          the input items in this menu.
	 */
	onInputChange : function(field) {
		var me = this, fields = me.fields, eq = fields.eq, gt = fields.gt, lt = fields.lt;

		if (field == eq) {
			if (gt) {
				gt.setValue(null);
			}
			if (lt) {
				lt.setValue(null);
			}
		} else {
			eq.setValue(null);
		}

		// restart the timer
		this.updateTask.delay(this.updateBuffer);
	}
});
